// Usage:
// 搜索镜像
// .\podw.exe search scylla
// 非常慢
// .\podw.exe  pull scylladb/scylla
// 速度稍微可以
//
//	.\podw.exe  pull hello-world
package main

import (
	"fmt"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"time"

	"github.com/spf13/cobra"
)

// 全局变量用于保存前缀
var mirrorPrefix string

// 默认搜索使用的前缀
const defaultSearchPrefix = "docker.xuanyuan.dev"

// 默认拉取使用的前缀
const defaultPullPrefix = "docker.xuanyuan.me"

var rootCmd = &cobra.Command{
	Use:   "podw",
	Short: "Podw 是一个容器镜像命令包装工具",
	Long:  `Podw 可以自动为镜像名称添加指定的镜像仓库前缀，支持在线搜索和拉取。`,
}

var pullCmd = &cobra.Command{
	Use:   "pull IMAGE",
	Short: "拉取镜像",
	Args:  cobra.MinimumNArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		image := args[0]

		// 如果用户没有显式设置前缀，使用默认拉取前缀
		prefix := mirrorPrefix
		if prefix == "" {
			prefix = defaultPullPrefix
		}

		newImage := fmt.Sprintf("%s/%s", prefix, image)

		if !isValidImageName(newImage) {
			fmt.Printf("镜像名称格式不正确: %s\n", newImage)
			return
		}

		containerRuntime, err := detectContainerRuntime()
		if err != nil {
			fmt.Println(err)
			return
		}

		fmt.Printf("正在使用 %s 拉取镜像: %s\n", containerRuntime, newImage)
		runCommand(containerRuntime, "pull", newImage)
	},
}

var searchCmd = &cobra.Command{
	Use:   "search KEYWORD",
	Short: "搜索镜像",
	Args:  cobra.MinimumNArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		keyword := args[0]

		// 如果用户没有显式设置前缀，使用默认搜索前缀
		prefix := mirrorPrefix
		if prefix == "" {
			prefix = defaultSearchPrefix
		}

		newKeyword := fmt.Sprintf("%s/%s", prefix, keyword)

		if !isValidImageName(newKeyword) {
			fmt.Printf("关键词格式不正确: %s\n", newKeyword)
			return
		}

		fmt.Printf("正在搜索镜像: %s\n", newKeyword)
		runCommand("podman", "search", newKeyword)
	},
}

func init() {
	// 设置 pull 命令的 prefix 标志
	pullCmd.Flags().StringVarP(&mirrorPrefix, "prefix", "p", "", "设置镜像仓库前缀（默认使用 "+defaultPullPrefix+"）")
	searchCmd.Flags().StringVarP(&mirrorPrefix, "prefix", "p", "", "设置镜像仓库前缀（默认使用 "+defaultSearchPrefix+"）")

	rootCmd.AddCommand(pullCmd)
	rootCmd.AddCommand(searchCmd)
}

func main() {
	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

// 执行命令并显示实时输出
func runCommand(command string, args ...string) {
	cmd := exec.Command(command, args...)

	stdout, _ := cmd.StdoutPipe()
	stderr, _ := cmd.StderrPipe()

	if err := cmd.Start(); err != nil {
		fmt.Printf("启动命令失败: %v\n", err)
		return
	}

	// 显示进度条
	ticker := time.NewTicker(time.Second)
	done := make(chan bool)
	go func() {
		for {
			select {
			case <-ticker.C:
				fmt.Print(".")
			case <-done:
				ticker.Stop()
				fmt.Println()
				return
			}
		}
	}()

	// 实时输出 stdout
	go func() {
		buf := make([]byte, 1024)
		for {
			n, err := stdout.Read(buf)
			if n > 0 {
				fmt.Print(strings.TrimSpace(string(buf[:n])))
			}
			if err != nil {
				break
			}
		}
	}()

	// 实时输出 stderr
	go func() {
		buf := make([]byte, 1024)
		for {
			n, err := stderr.Read(buf)
			if n > 0 {
				fmt.Fprint(os.Stderr, strings.TrimSpace(string(buf[:n])))
			}
			if err != nil {
				break
			}
		}
	}()

	if err := cmd.Wait(); err != nil {
		done <- true
		fmt.Printf("\n命令执行失败: %v\n", err)
		return
	}

	done <- true
	fmt.Println("命令执行完成")
}

// 验证镜像名称格式
func isValidImageName(image string) bool {
	pattern := `^([a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(:[0-9]+)?/)?([a-zA-Z0-9-._]+/)*[a-zA-Z0-9-._]+$`
	matched, err := regexp.MatchString(pattern, image)
	return err == nil && matched
}

// 检测可用的容器运行时
func detectContainerRuntime() (string, error) {
	runtimes := []string{"podman", "docker"}

	for _, rt := range runtimes {
		if _, err := exec.LookPath(rt); err == nil {
			if _, err := exec.Command(rt, "version").CombinedOutput(); err == nil {
				return rt, nil
			}
		}
	}

	return "", fmt.Errorf("未找到可用的容器运行时，请确保安装了 podman 或 docker")
}
